﻿using Library.Common.Common;
using Library.Common.Model;
using Library.Common.Serialize;
using Library.Core.Application;
using Library.Core.Application.BaseAction;
using Library.Core.Application.IInfrastructure;
using Library.Core.Application.IInfrastructure.Event;
using Synthesize.BaseSet.Application.MessageTopic;
using Synthesize.BaseSet.Domain.Aggregation.Consts;
using Synthesize.BaseSet.Domain.Aggregation.Entity.Authority;
using Synthesize.BaseSet.Domain.Event.Authority;
using Synthesize.BaseSet.Domain.Repository.Authority;
using Synthesize.BaseSet.Domain.Specifications.Authority.Role;
using Synthesize.BaseSet.ServiceInterface.Dtos.Authority.Role;
using Synthesize.BaseSet.ServiceInterface.UseCase.Authority;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Synthesize.BaseSet.Application.UseCase.Authority
{
    /// <summary>
    /// 角色操作逻辑
    /// </summary>
    public class RoleService : BaseService, IRoleService
    {

        private readonly IJwtFactory _jwtFactory;
        private readonly IEventBus _eventBus;
        private readonly IRoleRepository _roleRepository;
        private readonly IUserRoleRepository _userRoleRepository;
        private readonly IMenuPermissionRepository _menuPermissionRepository;
        private readonly IRoleMenuPermissionRepository _roleMenuPermissionRepository;
        private readonly IRoleMenuRepository _roleMenuRepository;
        private readonly IUserRepository _userRepository;

        public RoleService(IIocContainer container
            , IJwtFactory jwtFactory
            , IEventBus eventBus
            , IRoleRepository roleRepository
            , IUserRoleRepository userRoleRepository
            , IMenuPermissionRepository menuPermissionRepository
            , IRoleMenuPermissionRepository roleMenuPermissionRepository
            , IRoleMenuRepository roleMenuRepository
            , IUserRepository userRepository
            ) : base(container)
        {
            _jwtFactory = jwtFactory;
            _eventBus = eventBus;
            _roleRepository = roleRepository;
            _userRoleRepository = userRoleRepository;
            _menuPermissionRepository = menuPermissionRepository;
            _roleMenuPermissionRepository = roleMenuPermissionRepository;
            _roleMenuRepository = roleMenuRepository;
            _userRepository = userRepository;
        }

        /// <summary>
        /// 创建角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> Create(CreateRoleInput input)
        {
            return await HandleAsync(input, async () =>
            {
                var roleInfo = MapperHelper<CreateRoleInput, RoleInfoEntity>.Map(input);
                await new CreateRoleSpecification(_roleRepository).SatisfiedBy(roleInfo);

                roleInfo.Id = GuidHelper.GetSecuentialGuid();
                _roleRepository.Add(roleInfo);

                return await _roleRepository.SaveAsync();
            });
        }

        /// <summary>
        /// 禁用/启用角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> ForbidOrEnable(ForbidOrEnableInput input)
        {
            return await HandleAsync(input, async () =>
             {
                 var roleInfo = await _roleRepository.GetAsync(x => x.Id == input.Id);
                 if (roleInfo == null)
                 {
                     throw new ApplicationsException("无对应角色信息！");
                 }

                 roleInfo.Status = !roleInfo.Status;
                 _roleRepository.Update(roleInfo);
                 await _roleRepository.SaveAsync();

                 //如果被禁用，就删除角色的登录授权信息
                 if (!roleInfo.Status)
                 {
                     await NotifyForceLogOut(roleInfo);
                 }

                 return true;
             });
        }

        /// <summary>
        /// 更新角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> Update(UpdateRoleInput input)
        {

            return await HandleAsync(input, async () =>
            {

                var roleInfo = MapperHelper<UpdateRoleInput, RoleInfoEntity>.Map(input);
                await new UpdateRoleSpecification(_roleRepository).SatisfiedBy(roleInfo);
                _roleRepository.Update(roleInfo);

                //如果被禁用，就删除角色的登录授权信息
                if (!input.Status)
                {
                    await NotifyForceLogOut(roleInfo);
                }
                return await _roleRepository.SaveAsync();
            });
        }

        /// <summary>
        /// 修改角色对应的菜单权限信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> UpdateRoleMenu(UpdateRoleMenuInput input)
        {
            return await HandleAsync(input, async () =>
            {
                #region  角色可操作菜单
                //删除角色可操作菜单
                var roleMenus = await _roleMenuRepository.GetManyAsync(x => x.Platform == input.Platform && x.RoleId == input.RoleId);
                if (roleMenus.Any())
                {
                    _roleMenuRepository.UpdateIsDeletedRange(roleMenus);
                }

                //增加角色可操作菜单
                if (input.MenuIdList.Any())
                {
                    var roleMenuList = new List<RoleMenuReEntity>();
                    foreach (var item in input.MenuIdList)
                    {
                        roleMenuList.Add(new RoleMenuReEntity()
                        {
                            Id = GuidHelper.GetSecuentialGuid(),
                            MenuId = item,
                            RoleId = input.RoleId,
                            Platform = input.Platform,
                        });
                    }
                    _roleMenuRepository.AddRange(roleMenuList);
                }
                #endregion

                #region 角色可操作权限

                //删除角色可操作权限
                var roleMenuPermissions = await _roleMenuPermissionRepository.GetManyAsync(x => x.Platform == input.Platform && x.RoleId == input.RoleId);
                if (roleMenuPermissions.Any())
                {
                    foreach (var item in roleMenuPermissions)
                    {
                        _roleMenuPermissionRepository.Delete(item);
                    }
                }
                //增加角色可操作权限
                if (input.PermissionCodeList.Any())
                {
                    var menuPermissionList = await _menuPermissionRepository.GetManyAsync(x => input.PermissionCodeList.Contains(x.Code));
                    if (menuPermissionList.Any())
                    {
                        var roleMenuPermissionList = new List<RoleMenuPermissionReEntity>();
                        foreach (var item in menuPermissionList)
                        {
                            roleMenuPermissionList.Add(new RoleMenuPermissionReEntity()
                            {
                                Id = GuidHelper.GetSecuentialGuid(),
                                MenuId = item.MenuId,
                                MenuPermissionId = item.Id,
                                RoleId = input.RoleId,
                                Platform = input.Platform,
                            });
                        }
                        _roleMenuPermissionRepository.AddRange(roleMenuPermissionList);
                    }
                }

                #endregion

                return await _roleRepository.SaveAsync();
            });
        }

        /// <summary>
        /// 修改角色对应的用户信息
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> UpdateRoleUser(UpdateRoleUserInput input)
        {

            return await HandleAsync(input, async () =>
            {

                var userRoleList = await _userRoleRepository.GetManyAsync(x => input.RoleId.Equals(x.RoleId));
                if (userRoleList.Any())
                {
                    _userRoleRepository.UpdateIsDeletedRange(userRoleList);
                }

                var addUserRoles = new List<UserRoleReEntity>();
                if (input.UserIdList.Any())
                {
                    foreach (var item in input.UserIdList)
                    {
                        addUserRoles.Add(new UserRoleReEntity()
                        {
                            Id = GuidHelper.GetSecuentialGuid(),
                            RoleId = input.RoleId,
                            UserId = item
                        });
                    }
                    await _userRoleRepository.AddRangeAsync(addUserRoles);

                    //删除对应角色数据授权Redis缓存
                    var userIds = userRoleList.Where(x => !input.UserIdList.Contains(x.UserId)).Select(x => x.UserId).ToList();
                    if (userIds.Any())
                    {
                        await NotifyForceLogOut(userIds);
                    }
                }
                await _userRoleRepository.SaveAsync();

                return true;
            });
        }

        /// <summary>
        /// 删除角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> DeleteById(SingleDeleteInput input)
        {

            return await HandleAsync(input, async () =>
             {
                 var role = await _roleRepository.GetAsync(input.Id);

                 if (role == null)
                 {
                     throw new ApplicationsException("无对应角色信息存在！");
                 }
                 if (await _userRoleRepository.AnyAsync(x => x.RoleId.Equals(input.Id)))
                 {
                     throw new ApplicationsException("该角色存在人员信息，不能删除！");
                 }
                 _roleRepository.UpdateIsDeleted(role);
                 await _roleRepository.SaveAsync();

                 //删除对应角色数据授权Redis缓存
                 await NotifyForceLogOut(role);

                 return true;
             });
        }

        /// <summary>
        /// 批量删除角色
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> DeleteByIds(BatchDeleteInput input)
        {
            return await HandleAsync(input, async () =>
            {
                var roleList = await _roleRepository.GetManyAsync(x => input.Ids.Contains(x.Id));
                if (roleList.Any() && roleList.Count == input.Ids.Count)
                {
                    if (await _userRoleRepository.AnyAsync(x => input.Ids.Contains(x.RoleId)))
                    {
                        throw new ApplicationsException("有角色存在人员信息，不能删除！");
                    }

                    _roleRepository.UpdateIsDeletedRange(roleList);
                    await _roleRepository.SaveAsync();

                    //删除对应角色数据授权Redis缓存
                    foreach (var itemRole in roleList)
                    {
                        await NotifyForceLogOut(itemRole);
                    }
                }
                else
                {
                    throw new ApplicationsException("无对应角色信息存在！");
                }
                return true;
            });
        }

        /// <summary>
        /// 删除指定的用户-角色关系
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<BaseApiResult<bool>> DeleteUserRole(DeleteUserRoleInput input)
        {
            return await HandleAsync(input, async () =>
            {
                var userRole = await _userRoleRepository.GetAsync(x => input.RoleId.Equals(x.RoleId) && input.UserId.Equals(x.UserId));
                if (userRole != null)
                {
                    _userRoleRepository.UpdateIsDeleted(userRole);
                    await _roleRepository.SaveAsync();

                    //做强退通知
                    await NotifyForceLogOut(new List<Guid>() { userRole.UserId });
                }

                return true;
            });
        }

        /// <summary>
        /// 做强退通知
        /// 1、人员处于登录状态，该登录人员的角色被禁用，中心端、现场端、手持端需强制退出登录
        /// 2、权限改变，也需强制退出登录
        /// 3、人员设置中增加一个人员或减少一个人员，只需要将该角色下的当前人员登录的账号强制退出，该角色下的其他人员登录状态不发生改变
        /// </summary>
        /// <param name="roleInfo"></param>
        private async Task NotifyForceLogOut(RoleInfoEntity roleInfo)
        {
            var userRoleList = await _userRoleRepository.GetManyAsync(x => x.RoleId.Equals(roleInfo.Id));
            if (userRoleList.Any())
            {
                var title = "强制退出登录";
                var content = $"用户所属角色【{roleInfo.Name}】失效，需强制退出登录";

                var uIds = userRoleList.Select(x => x.UserId).ToList();
                var userList = await _userRepository.GetManyAsync(x => uIds.Contains(x.Id));

                await _jwtFactory.MakeUserAllTokenInvalid(userList.Select(x => x.UserName).ToList());
                if (userList.Count > 0)
                {
                    var messages = new List<SendMessageEvent>();
                    foreach (var item in userList)
                    {
                        await _eventBus.PublishAsync(TopicName.SendMessage,
                            new SendMessageEvent(
                                string.IsNullOrEmpty(title) ? "强制退出登录" : title,
                                string.IsNullOrEmpty(content) ? $"用户{item.UserName}关键信息变更，需强制退出登录" : content,
                                Guid.Empty,
                                item.Id,
                                DateTime.Now,
                                string.Empty,
                                string.Empty,
                                SendMessageCode.ForceLogOut
                           )
                        );
                    }
                }
            }
        }

        /// <summary>
        /// 做强退通知
        /// </summary>
        /// <param name="userIdList"></param>
        /// <returns></returns>
        private async Task NotifyForceLogOut(List<Guid> userIdList)
        {
            var userList = await _userRepository.GetManyAsync(x => userIdList.Contains(x.Id));

            await _jwtFactory.MakeUserAllTokenInvalid(userList.Select(x => x.UserName).ToList());
            if (userList.Count > 0)
            {
                var messages = new List<SendMessageEvent>();
                foreach (var item in userList)
                {
                    await _eventBus.PublishAsync(TopicName.SendMessage,
                        new SendMessageEvent(
                            "强制退出登录",
                            $"用户{item.UserName}关键信息变更，需强制退出登录",
                            Guid.Empty,
                            item.Id,
                            DateTime.Now,
                            string.Empty,
                            string.Empty,
                            SendMessageCode.ForceLogOut
                       )
                    );
                }
            }
        }
    }
}
